<?php
namespace Tbf\Bundle\SerializerBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Tbf\Bundle\SerializerBundle\Exception\SerializerException;

/**
 * 注册handler
 */
class HandlerRegistryCompilerPass implements CompilerPassInterface
{
    static $handler_map = array(
        'Tbf\Bundle\SerializerBundle\Handler\LoadFromArray\LoadFromArrayInterface'=>'LoadFromArray',
        'Tbf\Bundle\SerializerBundle\Handler\ToArray\ToArrayInterface'=>'ToArray',
        'Tbf\Bundle\SerializerBundle\Handler\NewFromArray\NewFromArrayInterface'=>'NewFromArray',
    );

    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('tbf_serializer.handler_register')) {
            return;
        }
        $register_definition = $container->getDefinition('tbf_serializer.handler_register');
        $handler_list = $container->findTaggedServiceIds(
            'tbf_serializer.handler'
        );
        $map = array();
        foreach ($handler_list as $handler_id=>$dispatcher_attributes) {
            $serializer_class_name = $container->getDefinition($handler_id)->getClass();
            $meta_serializer_class = new \ReflectionClass($serializer_class_name);
            $serializer_interface_map =  array_fill_keys($meta_serializer_class->getInterfaceNames(),1);
            if (!empty($dispatcher_attributes[0]['class_name'])) {
                $class_name =  $dispatcher_attributes[0]['class_name'];
            }else{
                if(empty($serializer_interface_map['Tbf\Bundle\SerializerBundle\Handler\ClassNameAwareHandlerInterface'])){
                    throw new SerializerException(
                        'need an attribute of class_name on tag tbf_serializer.handler or implement ClassNameAwareHandlerInterface');
                }
                $class_name = call_user_func(array($serializer_class_name,'getSerializeClassName'));
            }
            if (!empty($serializer_interface_map['Tbf\Bundle\SerializerBundle\SerializerAwareInterface'])){
                $container->getDefinition($handler_id)->addMethodCall(
                    'setSerializer',array(new Reference('tbf_serializer'))
                );
            }
            //TODO reflect some code to make it more general...
            if (!empty($serializer_interface_map['Symfony\Component\DependencyInjection\ContainerAwareInterface'])){
                //TODO repeat setContainer problem...
                $container->getDefinition($handler_id)->addMethodCall(
                    'setContainer',array(new Reference('service_container'))
                );
            }
            $class_name = ltrim($class_name,'\\');
            $interface_num = 0;
            foreach(self::$handler_map as $interface_name=>$type_name){
                if (!empty($serializer_interface_map[$interface_name])){
                    $map[$type_name][$class_name]=$handler_id;
                    $interface_num+=1;
                }
            }
            if ($interface_num===0){
                throw new SerializerException(
                    sprintf('a handler must implement LoadFromArrayInterface or ToArrayInterface or NewFromArrayInterface'.
                        'service_id:%s ,class_name:%s',
                        $handler_id,$serializer_class_name
                    ));
            }
            $container->addClassResource(new \ReflectionClass($class_name));
        }
        if (!empty($map)){
            $register_definition->addMethodCall(
                'registerByServiceIdMap',
                array($map)
            );
        }
    }
}
